assert(PandaDKPMaster, "PandaDKPMaster not found!")

------------------------------
--      Are you local?      --
------------------------------
local PandaDKPMaster = PandaDKPMaster
local Events =
{
   UI = {},
}
PandaDKPMaster.Events = Events


function Events:Enable()
   Events:SetupUI()
end



function Events:SummarizeEvents(olderThen)
   -- Find all events older then the specified date
   local function Matches(event, arg)
      if (tonumber(event.ts) < arg) then
         return true
      end
      return false
   end
   local toRemove = Events:FindEvents(Matches, tonumber(olderThen))
   
   -- Remove all the events listed in toRemove
   for i, md5 in pairs(toRemove) do
      Events:SummarizeEvent(md5)
      PandaDKPMaster.db.realm.DKP.Events[md5] = nil
   end
   
   -- If there were any events to summarize, then the checksum is wrong
   if (#(toRemove) > 0) then PandaDKPMaster.Sync:ResetChecksum('DKP', olderThen) end
end



function Events:SummarizeEvent(md5)
   local event = PandaDKPMaster.db.realm.DKP.Events[md5]
   if ("SI" == event.type) then
      -- do nothing
   elseif ("AA" == event.type) then
      -- do nothing
   elseif ("AW" == event.type) then
      -- add the award to each players historical DKP
      for i, player in pairs(event.players) do
         PandaDKPMaster.Players:AddHistoricalDKP(player, event.dkp, event.pool)
      end
   elseif ("PI" == event.type) then
      -- subtract the purchase from the player's historical DKP
      PandaDKPMaster.Players:AddHistoricalDKP(event.player, event.dkp * -1, event.pool)
   else
      PandaDKPMaster:Print(string.format("WARNING! An unknown event of type '%s' was found in your local database!", event.type))
   end
end


function Events:FindEvents(matching, arg)
   local matches = {}
   for md5, event in pairs(PandaDKPMaster.db.realm.DKP.Events) do
      if (matching(event, arg)) then tinsert(matches, md5) end
   end
   return matches
end


function Events:InsertSetItemEvent(timestamp, itemId, dkp, pool, type, subtype, name)
   dkp = tonumber(string.format("%0.2f", dkp))
   local message = PandaDKPMaster.Messages:CreateSIMessage(timestamp, itemId, dkp, pool, type, subtype, name)
   local md5 = PandaDKPMaster.MD5Lib:MD5(message)
   
   -- Insert the item in the main database
   local event =
   {
      type = "SI",
      ts = timestamp,
      itemId = itemId,
      dkp = dkp,
      pool = pool,
      itemtype = type,
      subtype = subtype,
      name = name,
   }
   PandaDKPMaster.db.realm.DKP.Events[md5] = event
   
   -- Make sure we have the pool in our database
   PandaDKPMaster.Pools:AddPool(pool)
   
   -- If there are no newer SI events for this item, set the item's DKP
   local function Matches(event, arg)
      if (event.type == "SI" and event.itemId == arg.itemId and tonumber(event.ts) > arg.ts) then
         return true
      end
      return false
   end
   local matches = Events:FindEvents(Matches, {ts = tonumber(timestamp), itemId = itemId})
   if (#(matches) == 0) then
      PandaDKPMaster.Items:SetItemValue(itemId, dkp, pool, type, subtype, name)
   end
   
   -- Update checksums
   PandaDKPMaster.Sync:ResetChecksum('ITEM', timestamp)
   PandaDKPMaster.Sync:ResetChecksum('EVENT', timestamp)
   
   Events:RefilterEventList()
end


function Events:InsertPurchaseItemEvent(timestamp, pool, dkp, itemId, player, lootNum, needOrGreed)
   dkp = tonumber(string.format("%0.2f", dkp))
   local message = PandaDKPMaster.Messages:CreatePIMessage(timestamp, pool, dkp, itemId, player, lootNum, needOrGreed)
   local md5 = PandaDKPMaster.MD5Lib:MD5(message)
   
   -- Insert the item in the main database
   local event =
   {
      type = "PI",
      ts = timestamp,
      pool = pool,
      dkp = dkp,
      itemId = itemId,
      player = player,
      lootNum = lootNum,
      needOrGreed = needOrGreed,
   }
   PandaDKPMaster.db.realm.DKP.Events[md5] = event
   
   -- Make sure we have the pool in our database
   PandaDKPMaster.Pools:AddPool(pool)
   
   -- Deduct the player's DKP
   PandaDKPMaster.Players:AddDKP(player, dkp * -1, pool)
   
   -- Update checksums
   PandaDKPMaster.Sync:ResetChecksum('EVENT', timestamp)
   
   Events:RefilterEventList()
end


function Events:InsertAwardEvent(timestamp, pool, dkp, notes, players)
   dkp = tonumber(string.format("%0.2f", dkp))
   sort(players)
   local message = PandaDKPMaster.Messages:CreateAWMessage(timestamp, pool, dkp, notes, players)
   local md5 = PandaDKPMaster.MD5Lib:MD5(message)
   
   -- Insert the item in the main database
   local event =
   {
      type = "AW",
      ts = timestamp,
      pool = pool,
      dkp = dkp,
      notes = notes,
      players = players,
   }
   PandaDKPMaster.db.realm.DKP.Events[md5] = event
   
   -- Make sure we have the pool in our database
   PandaDKPMaster.Pools:AddPool(pool)
   
   -- Give each player that much DKP
   for i, player in pairs(players) do
      PandaDKPMaster.Players:AddDKP(player, dkp, pool)
   end
   
   -- Update checksums
   PandaDKPMaster.Sync:ResetChecksum('EVENT', timestamp)
   
   Events:RefilterEventList()
end


function Events:InsertAliasEvent(timestamp, main, alias)
   local message = PandaDKPMaster.Messages:CreateAAMessage(timestamp, main, alias)
   local md5 = PandaDKPMaster.MD5Lib:MD5(message)
   
   -- Insert the item in the main database
   local event =
   {
      type = "AA",
      ts = timestamp,
      main = main,
      alias = alias,
   }
   PandaDKPMaster.db.realm.DKP.Events[md5] = event
   
   -- Give each player that much DKP
   for i, player in pairs(players) do
      PandaDKPMaster.Players:AddDKP(player, dkp, pool)
   end
   
   -- Update checksums
   PandaDKPMaster.Sync:ResetChecksum('EVENT', timestamp)
   
   Events:RefilterEventList()
end


function Events:SendEvent(md5)
   local event = PandaDKPMaster.db.realm.DKP.Events[md5]
   local message = nil
   if (nil ~= event) then
      if ('PI' == event.type) then
         message = PandaDKPMaster.Messages:CreatePIMessage(event.ts, event.pool, event.dkp, event.itemId, event.player, event.lootNum, event.needOrGreed)
      elseif ('AW' == event.type) then
         message = PandaDKPMaster.Messages:CreateAWMessage(event.ts, event.pool, event.dkp, event.notes, event.players)
      elseif ('SI' == event.type) then
         message = PandaDKPMaster.Messages:CreateSIMessage(event.ts, event.itemId, event.dkp, event.pool, event.itemtype, event.subtype, event.name)
      end
   end
   
   if (nil ~= message) then
      PandaDKPMaster.Comm:Send("GUILD", message)
   end
end





----------------------
--   Interface UI   --
----------------------

function Events:SetupUI()
   Events.UI.ShowAllTypes = true
   Events.UI.ShowAllPlayers = true
   Events.UI.ShowAllDates = true
   Events.UI.ShowTypes = {}
   Events.UI.ShowPlayers = {}
   Events.UI.ShowDates = {}
   
   Events:RefilterEventList()
end


function Events:ShowFilterMenu()
end

function Events:RefilterEventList()
   Events.UI.EventList = {}
   
   local function EventFilter(event, arg)
      if (not Events.UI.ShowAllTypes) then
         if (nil == Events.UI.ShowTypes[event.type] or false == Events.UI.ShowTypes[event.type]) then
            return false
         end
      end
      if (not Events.UI.ShowAllPlayers) then
         if ("AW" == event.type) then
            -- If any player we're supposed to show is in the award list, show it
            local inList = false
            for i, player in pairs(event.players) do
               if (nil ~= Events.UI.ShowPlayers[player] and true == Events.UI.ShowPlayers[player]) then
                  inList = true
                  break
               end
            end
            if (not inList) then return false end
         elseif ("PI" == event.type) then
            -- If the player purchased it, show it
            if (nil == Events.UI.ShowPlayers[event.player] or false == Events.UI.ShowPlayers[event.player]) then
               return false
            end
         else
            -- Its not an event with player info, so don't show it
            return false
         end
      end
      if (not Events.UI.ShowAllDates) then
         local ts = PandaDKPMaster:GetDatestamp(event.ts)
         if (nil == Events.UI.ShowDates[ts] or false == Events.UI.ShowDates[ts]) then
            return false
         end
      end
      
      return true
   end
   
   -- Find all events that match the filter
   local matches = Events:FindEvents(EventFilter, nil)
   for i, md5 in pairs(matches) do
      tinsert(Events.UI.EventList, PandaDKPMaster.db.realm.DKP.Events[md5])
   end
   
   -- Sort the list according to timestamp
   local function SortList(a, b)
      return a.ts < b.ts
   end
   sort(Events.UI.EventList, SortList)
   
   Events:EventListUpdate()
end



local kTypeToText = { AW = 'Award', SI = 'Item', PI = 'Purchase', AA = 'Add Alias', RA = 'Remove Alias' }
function Events:EventListUpdate()
   local numEntries = #(Events.UI.EventList)
   FauxScrollFrame_Update(PDKPM_EventsConfigListScrollFrame, numEntries, 16, 16, nil, 350, 350, nil, 350, 350, true)
   
   local line
   local offset
   
   for line = 1, 16 do
      offset = line + FauxScrollFrame_GetOffset(PDKPM_EventsConfigListScrollFrame)
      local button = getglobal("PDKPM_EventsConfigListEventLine"..line)
      local event = Events.UI.EventList[offset]
      button:SetID(offset)
      if (offset <= numEntries) then
         local text = getglobal("PDKPM_EventsConfigListEventLine"..line.."Type")
         text:SetText(kTypeToText[event.type])
         text = getglobal("PDKPM_EventsConfigListEventLine"..line.."Timestamp")
         text:SetText(PandaDKPMaster:TimestampToTimeString(event.ts))
         text = getglobal("PDKPM_EventsConfigListEventLine"..line.."Description")
         if ("SI" == event.type) then
            local _, itemLink = GetItemInfo(event.itemId)
            if (nil == itemLink) then itemLink = event.itemId end
            text:SetText(string.format("%s is now worth %i DKP from '%s'.", itemLink, event.dkp, event.pool))
         elseif ("AA" == event.type) then
         elseif ("RA" == event.type) then
         elseif ("AW" == event.type) then
            local names = {}
            local players = event.players  sort(players)
            for i, player in pairs(players) do
               tinsert(names, string.format("|cff%s%s|r", PandaDKPMaster:getClassHex(PandaDKPMaster.Players:Class(player)), player))
            end
            text:SetText(string.format("Award '%s' granted %.2f DKP in '%s' to %s", event.notes, event.dkp, event.pool, table.concat(names, ', ')))
         elseif ("PI" == event.type) then
            local _, itemLink = GetItemInfo(event.itemId)
            local hex = PandaDKPMaster:getClassHex(PandaDKPMaster.Players:Class(event.player))
            if (nil == itemLink) then itemLink = event.itemId end
            text:SetText(string.format("|cff%s%s|r purchased %s for %.2f DKP from '%s'.", hex, event.player, itemLink, event.dkp, event.pool))
         else
            text:SetText(string.format("WARNING! An unknown event of type '%s' was found in your local database!", event.type))
         end
         button:Show()
      else
         button:Hide()
      end
   end
   
end

function Events:EventListMouseover(line)
   local type = getglobal(line:GetName() .. "Type")
   local ts = getglobal(line:GetName() .. "Timestamp")
   local desr = getglobal(line:GetName() .. "Description")
   
   GameTooltip:SetOwner(line, "ANCHOR_TOPLEFT", 0, 10)
   GameTooltip:ClearLines()
   GameTooltip:AddDoubleLine(type:GetText(), ts:GetText())
   GameTooltip:AddLine(" ")
   GameTooltip:AddLine(desr:GetText(), 1, 1, 1, true)
   GameTooltip:Show()
end